﻿using CloudStorageLight.DesktopTool.Odata.CloudStorageLight.Core;
using CloudStorageLight.DesktopTool.Odata.StorageService;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace CloudStorageLight.DesktopTool
{
    public class UploadFile
    {
        public UploadFile()
        {
            ContentType = "application/octet-stream";
        }
        public string Name { get; set; }
        public string Filename { get; set; }
        public string ContentType { get; set; }
        public Stream Stream { get; set; }
    }

    public class CloudStorageLightClient
    {
        private string baseUrl;
        private string user;
        private string pass;

        private Container OdataClient;

        public CloudStorageLightClient(string baseUrl, string user, string pass)
        {
            this.baseUrl = baseUrl;
            this.user = user;
            this.pass = pass;
            OdataClient = new Container(new Uri(baseUrl + "/Odata"));
            OdataClient.SendingRequest2 += OdataClient_SendingRequest2;
        }

        void OdataClient_SendingRequest2(object sender, Microsoft.OData.Client.SendingRequest2EventArgs e)
        {
            e.RequestMessage.SetHeader(HttpRequestHeader.Authorization.ToString(),
                "Basic " + Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(user+":"+pass)));
        }

        public void Upload(string path, string filename)
        {
            string id;
            using (var stream = File.Open(filename, FileMode.Open))
            {
                var file = new UploadFile();
                file.Filename = filename;
                file.Name = Path.GetFileName(filename);
                file.Stream = stream;

                var values = new NameValueCollection();

                var ret = UploadFiles(baseUrl + "/f" + path, new UploadFile[] { file }, values, user, pass);
                Debug.WriteLine(Encoding.UTF8.GetString(ret));
                id = PathToId(path + file.Name);

            }
            var item = OdataClient.CreateQuery<FileItem>("Data").ByKey(new Dictionary<string, object>() { { "Id", id } });
            var text = Extractor.Extract(filename);
            var title = item.GetValue().Title;
            var result = item.UpdateSearchContent(title, text).GetValue();
        }

        public void UploadAsImage(string path, string filename)
        {
            string outputFolder = Path.Combine(Path.GetDirectoryName(filename), "output");
            var filetype = Path.GetExtension(filename).Replace(".", "");
            var converter = DocumentImageConverterRepository.GetConverter(filetype);

            if (Directory.Exists(outputFolder))
            {
                Directory.Delete(outputFolder, true);
            }
            Directory.CreateDirectory(outputFolder);

            var outfilePattern = Path.Combine(outputFolder, Path.GetFileNameWithoutExtension(filename)+ ".jpg");
            var images = converter.ToImageFile(filename, outfilePattern, int.MaxValue);
            var texts = converter.ToText(filename, outputFolder, int.MaxValue);

            for (int i = 0; i < images.Count; i++)
            {
                string id;
                var imgfile = images[i];
                using (var stream = File.Open(imgfile, FileMode.Open))
                {
                    var file = new UploadFile();
                    file.Filename = imgfile;
                    file.Name = Path.GetFileName(imgfile);
                    file.Stream = stream;
                    var imgPath = path + Path.GetFileName(filename) + "/" ;

                    var values = new NameValueCollection();
                    var ret = UploadFiles(baseUrl + "/f" + imgPath, new UploadFile[] { file }, values, user, pass);
                    id = PathToId(imgPath + file.Name);
                }
                var item = OdataClient.CreateQuery<FileItem>("Data").ByKey(new Dictionary<string, object>() { { "Id", id } });
                var text = texts[i];
                var title = Path.GetFileName(filename);
                var result = item.UpdateSearchContent(title, text).GetValue();
            }
        }

        
        private string PathToId(string str)
        {
            return str.Replace("/", "|").Replace(".", "*");
        }

        private byte[] UploadFiles(string address, IEnumerable<UploadFile> files, NameValueCollection values, string user, string pass)
        {
            var request = WebRequest.Create(address);
            request.Headers.Add(HttpRequestHeader.Authorization.ToString(), "Basic " + Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes( user +":" + pass)));

            request.Method = "POST";
            var boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x", NumberFormatInfo.InvariantInfo);
            request.ContentType = "multipart/form-data; boundary=" + boundary;
            boundary = "--" + boundary;

            using (var requestStream = request.GetRequestStream())
            {
                // Write the values
                foreach (string name in values.Keys)
                {
                    var buffer = Encoding.ASCII.GetBytes(boundary + Environment.NewLine);
                    requestStream.Write(buffer, 0, buffer.Length);
                    buffer = Encoding.ASCII.GetBytes(string.Format("Content-Disposition: form-data; name=\"{0}\"{1}{1}", name, Environment.NewLine));
                    requestStream.Write(buffer, 0, buffer.Length);
                    buffer = Encoding.UTF8.GetBytes(values[name] + Environment.NewLine);
                    requestStream.Write(buffer, 0, buffer.Length);
                }

                // Write the files
                foreach (var file in files)
                {
                    var buffer = Encoding.ASCII.GetBytes(boundary + Environment.NewLine);
                    requestStream.Write(buffer, 0, buffer.Length);
                    buffer = Encoding.UTF8.GetBytes(string.Format("Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"{2}", file.Name, file.Filename, Environment.NewLine));
                    requestStream.Write(buffer, 0, buffer.Length);
                    buffer = Encoding.ASCII.GetBytes(string.Format("Content-Type: {0}{1}{1}", file.ContentType, Environment.NewLine));
                    requestStream.Write(buffer, 0, buffer.Length);
                    file.Stream.CopyTo(requestStream);
                    buffer = Encoding.ASCII.GetBytes(Environment.NewLine);
                    requestStream.Write(buffer, 0, buffer.Length);
                }

                var boundaryBuffer = Encoding.ASCII.GetBytes(boundary + "--");
                requestStream.Write(boundaryBuffer, 0, boundaryBuffer.Length);
            }

            using (var response = request.GetResponse())
            using (var responseStream = response.GetResponseStream())
            using (var stream = new MemoryStream())
            {
                responseStream.CopyTo(stream);
                return stream.ToArray();
            }
        }

    }
}
